﻿/*
Copyright (c) 2010 Lance Ward
This software is licensed under the MIT license, except where otherwise noted.
For complete license details, refer to license.txt
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace ADNLib
{

    public enum ToolSelectorMode
    {
        Rotate,
        MoveSize,
        None
    }

	[XmlInclude(typeof(Shape))]
	[XmlInclude(typeof(XGroup))]
    [XmlInclude(typeof(Motion))]
    [Serializable]
	public class XObject
	{
		private XObjectType type = XObjectType.Shape;
		private List<Motion> motions = new List<Motion>(); //here because motions can be applied to both groups and shapes
        private string name = "Object";

		[XmlAttribute]
		public XObjectType Type
		{
			get { return type; }
			set { type = value; }
		}

		[XmlElement("MOTION")]
		public List<Motion> Motions
		{
			get { return motions; }
			set { motions = value; }
		}

		[XmlElement]
		public string Name
		{
			get { return name; }
			set { name = value; }
		}

        [XmlIgnore]
        public PointF CenterPoint
        {
            get { return GetCenterPoint(); }
        }

		public virtual bool HitTest(Graphics g, PointF p) { return false; }
		public virtual bool HitTest(Graphics g, RectangleF r) { return false; }	//tests if a shape is contained in a rect
		public virtual void Move(PointF amount) { }
		public virtual void Draw(Graphics g) { }
		public virtual void DrawGhost(Graphics g) { }
        public virtual void DrawTextMarker(Graphics g, int position) { }
        public virtual void DrawPathMarkers(Graphics g, List<PathPoint> selMarkers) { }
        public virtual ShapeBezier ConvertToPath(){return null;}
        public virtual void Rotate(PointF centerPoint, PointF controlPoint) { }
        public virtual void Rotate(float angle){}
        public virtual void Resize(SizeDirection direction, PointF amount) { }


		[XmlIgnore]
		public virtual RectangleF Bounds
		{
			get { return RectangleF.Empty; }
		}

		public virtual void DrawSelectors(Graphics g, ToolSelectorMode mode, bool drawAnim)
		{
            if (!drawAnim)
            {
                PointF[] points = GetRectPoints(this.Bounds);
                for (int i = 0; i < points.Length; i++)
                {
                    DrawSelector(g, points[i], mode);
                }
            }
            else
            {
                float zoom = g.Transform.Elements[0];
                Pen p = new Pen(Color.Fuchsia, 3.0f / zoom);
                p.DashStyle = DashStyle.Solid;
                g.DrawRectangle(p, this.Bounds.X, this.Bounds.Y, this.Bounds.Width, this.Bounds.Height);
            }
		}

		protected void DrawSelector(Graphics g, PointF pt, ToolSelectorMode mode)
		{
			float zoom = g.Transform.Elements[0];

			RectangleF rect = new RectangleF(pt.X - (4.0f / zoom), pt.Y - (4.0f / zoom), (8.0f / zoom), (8.0f / zoom));
            Pen p = new Pen(Color.Black, (1.0f / zoom));

            if (mode == ToolSelectorMode.Rotate)
            {
                Brush b = new SolidBrush(Color.Red);
                g.FillEllipse(b, rect);
                g.DrawEllipse(p, rect.X, rect.Y, rect.Width, rect.Height);
            }
            else  //rotate
            {
                Brush b = new SolidBrush(Color.Blue);
                g.FillRectangle(b, rect);
                g.DrawRectangle(p, rect.X, rect.Y, rect.Width, rect.Height);
            }
		}

		protected PointF[] GetRectPoints(RectangleF rect)
		{
			PointF[] points = new PointF[8];	//

			//top, left
			points[0] = new PointF(rect.Left, rect.Top);
			//top, center
			points[1] = new PointF((rect.Right + rect.Left) / 2, rect.Top);
			//top, right
			points[2] = new PointF(rect.Right, rect.Top);


			//left, center
			points[3] = new PointF(rect.Left, (rect.Bottom + rect.Top) / 2);
			//right, center
			points[4] = new PointF(rect.Right, (rect.Bottom + rect.Top) / 2);

			//bottom, left
			points[5] = new PointF(rect.Left, rect.Bottom);
			//bottom, center
			points[6] = new PointF((rect.Right + rect.Left) / 2, rect.Bottom);
			//bottom, right
			points[7] = new PointF(rect.Right, rect.Bottom);


			return points;
		}

		public virtual int HitTestSelectors(Graphics g, PointF p, ToolSelectorMode mode)
		{
			float zoom = g.Transform.Elements[0];

			PointF[] points = GetRectPoints(this.Bounds);
			GraphicsPath path = new GraphicsPath();

			for (int i = 0; i < points.Length; i++)
			{
				RectangleF rect = new RectangleF(points[i].X - (4.0f / zoom), points[i].Y - (4.0f / zoom), (8.0f / zoom), (8.0f / zoom));

                if (mode == ToolSelectorMode.MoveSize) { path.AddRectangle(rect); }
                else { path.AddEllipse(rect); }

				if (path.IsVisible(p)) { return i; }
				path.ClearMarkers();
			}

			return -1;
		}

		public virtual int HitTestPathMarkers(Graphics g, PointF p)
		{
			return -1;
		}

        protected virtual PointF GetCenterPoint()
        {
            return new PointF(this.Bounds.X + (this.Bounds.Width / 2.0f), this.Bounds.Y + (this.Bounds.Height / 2.0f));
        }

        public float GetAngle(PointF p1, PointF p2)
        {
            float x = p2.X - p1.X;
            float y = p2.Y - p1.Y;

            float a = (float)(Math.Atan2(y, x) * 180.0 / Math.PI);
            if (a < 0) { a = 270 + (90 - Math.Abs(a)); }

            return a;
        }

        public virtual void FlipHoriz(float offset)
        {

        }

        public virtual void FlipVert(float offset)
        {

        }
	}

	public enum XObjectType
	{
		Group,
		Shape
	}
}
